[Linux内核设计与实现]系统调用

内核提供接口让应用程序调用实现特定功能,避免应用程序肆意妄为。

与内核通信

系统调用在用户空间进程和硬件设备间添加了一个中间层。

  1. 提供硬件的抽象接口,即无需管磁盘类型,介质等问题。
  2. 保证系统的安全。
  3. 告知内核自己在使用硬件以实现多任务和虚拟内存。内核知道了才能更好的管理分配。
    系统调用是用户空间访问内核的唯一手段。

API、POSIX、和C库

用户程序在用户空间使用API进行编程。API可以实现零个,一个或多个系统调用。
UNIX世界中,最流行的应用程序接口是基于POSIX标准的。在大多数Unix上,根据POSIX定义的API函数和系统调用之间有着直接的关系。这个协议是对操作系统服务接口的标准化,从而保证了应用程序在源码层次的可移植性。
具体来说是应用程序调用API,API中包含有系统调用,调用内核。
程序员与API打交道,内核与系统调用打交道。

系统调用

要访问系统调用(在Linux中常称为syscall),通常通过C库中定义的函数调用来进行。

系统调用号

在Linux中,每个系统调用被赋予一个系统调用号。通过这个独一无二的号可以关联系统调用。系统调用号非常重要,一旦分配就不能变更,否则编译好的应用就会崩溃。Linux中的sys_ni_syscall()系统调用几乎不做任何操作,相当于白板儿,用来替代那些被删除的或不可用的系统调用。
内核用sys_call_table记录注册过的系统调用。

系统调用的性能

Linux系统调用比其他操作系统执行的快。一是因为Linux有很短的上下文切换时间。二是系统调用处理程序和每个系统调用都很简洁。

系统调用的处理程序

应用程序实际在API中调用的系统调用也并不是直接执行内核代码。应用程序以软中断的方式来通知系统执行一个系统的调用。通过引发异常来促使系统切换到内核态去执行异常处理程序。正是系统调用的处理程序。通过int$0x80指令触发中断。

指定恰当的系统调用

系统调用号通过eax寄存器传递给内核。

参数传递

也可以通过寄存器进行参数的传递。

系统调用的实现

实现系统调用

Unix格言提供机制而不是策略,当写一个系统调用时,要时刻注意可移植性和健壮性,还要为以后做打算。

参数验证

系统调用必须仔细检查参数是否合法有效最重要的检查是用户提供的指针知否有效。内核无论何时都不能轻率接受来自用户空间的指针。

系统调用上下文

在Context中,内核可以休眠可以被抢占。

绑定一个系统调用的最后步骤

从用户空间访问系统调用